#include					<iostream>
#include					"Player.h"
#include					"time.h"

Player::Player(Time & time) : _time(time), _stream(NULL), _volume(1)
{
	_sample_rate = 44100;
	_frames_per_buffer = 240;
	_num_channels = 2;
}

Player::~Player()
{
	if (_stream)
		Pa_CloseStream(_stream);
}

static int					playCallback( const void *inputBuffer, void *outputBuffer,
                              unsigned long framesPerBuffer,
                              const PaStreamCallbackTimeInfo* timeInfo,
                              PaStreamCallbackFlags statusFlags,
                              void *userData)
{
	Player			*speaker = reinterpret_cast<Player *>(userData);

	return speaker->playCall((short *) outputBuffer, framesPerBuffer);
}

int							Player::playCall(short *outputBuffer, unsigned long fpb)
{
  SoundPacket *packet = NULL;
  size_t to_calc = fpb * _num_channels;
  _mutex.lock();
  for (size_t j = 0; j < to_calc; ++j)
    outputBuffer[j] = 0;
  if (!_buffer.empty())
    {
      for (std::map<unsigned int, StreamCircularBuffer*>::iterator it = _buffer.begin(); it != _buffer.end(); ++it)
	{
	  packet = (*it).second->get();
	  if (packet)
	    {
	      for (size_t j = 0; j < to_calc; ++j)
			{
			if (packet && packet->current_index >= packet->len())
			{
				(*it).second->next();
				packet = (*it).second->get();
			}
			if (packet != NULL)
				{
					outputBuffer[j] += (short)(packet->data()[packet->current_index] * 0.8f * _volume);
					packet->current_index++;
				}
			}
	    }
	}
  }
  _mutex.unlock();
  return _status;
}

void						Player::setVolume(float volume)
{
	if (volume >= 0 && volume <= 1)
		_volume = volume;
}

void						Player::start()
{
	PaError		err;

	err = Pa_Initialize();
	if( err == paNoError )
	{
		_outputParameters.device = Pa_GetDefaultOutputDevice();
		if (_outputParameters.device > 0)
		{
			_outputParameters.channelCount = _num_channels;
		    _outputParameters.sampleFormat =  paInt16;
			_outputParameters.suggestedLatency = Pa_GetDeviceInfo(_outputParameters.device)->defaultLowOutputLatency;
		    _outputParameters.hostApiSpecificStreamInfo = NULL;
		   err = Pa_OpenStream(&_stream, NULL, &_outputParameters,
				_sample_rate, paFramesPerBufferUnspecified, paClipOff,
				playCallback, this);
		   if (err != paNoError)
			   std::cout << "[CRITICAL] can't open stream" << std::endl;
		}
		else
			std::cout << "[CRITICAL] can't open audio device" << std::endl;
	}
	else
		std::cout << "[CRITICAL] can't initialize audio lib" << std::endl;
}

void						Player::stop()
{
	std::cout << "play [OFF]" << std::endl;
	_status = paComplete;
	Pa_StopStream(_stream);
}

void						Player::play()
{
	if(_stream)
	{
		std::cout << "play [ON]" << std::endl;
		_status = paContinue;
		Pa_StartStream(_stream);
	}
	else
		std::cout << "error on play" << std::endl;
}

void						Player::newBuffer(unsigned int id)
{
	_mutex.lock();
	if (_buffer.find(id) == _buffer.end())
		_buffer[id] = new StreamCircularBuffer(500, _frames_per_buffer * _num_channels);
	else
		std::cout << "Error : Buffer already exist" << std::endl;
	_mutex.unlock();
}

void						Player::destroyBuffer(unsigned int id)
{
	_mutex.lock();
	if (_buffer.find(id) != _buffer.end())
	{
		delete _buffer[id];
		_buffer.erase(id);
	}
	else
		std::cout << "Error : Buffer doesn't exist" << std::endl;
	_mutex.unlock();
}

SoundPacket					*Player::getSoundPacket(unsigned int id)
{
	SoundPacket				*ret = NULL;
	_mutex.lock();
	if (_buffer.find(id) != _buffer.end())
		ret = _buffer[id]->getPacket();
	_mutex.unlock();
	return ret;
}

void						Player::packetReady(unsigned int id)
{
  _mutex.lock();
  if (_buffer.find(id) != _buffer.end())
    _buffer[id]->packetReady();
  _mutex.unlock();
}
